#!/bin/bash

declare -i ret_ok=0                             # 成功
declare -i ret_failed_param_wrong=1             # 失败 参数错误
declare -i ret_failed_crl_format_check=2        # 失败 CRL文件格式错误
declare -i ret_failed_crl_same_old_crl=3        # 失败 导入的crl文件与本地的相同
declare -i ret_failed_crl_compare_update_time=4 # 失败 导入的crl文件比本地的crl更旧
declare -i ret_failed_crl_update=5              # 失败 CRL文件更新失败
declare -i ret_failed_verify_crl=6              # 失败 CRL文件校验失败
declare -i ret_crl_need_update=7                # 本地crl文件 需要更新

WORK_PATH="/opt/middleware/AtlasEdge"
SCRIPT_PATH="/opt/middleware/AtlasEdge/software/edge_site/edge_manager/src/script"
SAVE_CRL_PATH="/etc/hwsipcrl/"
SAVE_CRL_FILE_NAME="ascendsip.crl"
CRL_PATH=""
STATE_SAME=0
STATE_NEW=1
STATE_OLD=2
CRL_MAXSIZE=32768  # crl 文件最大限制为32k

. ${SCRIPT_PATH}/log_util.sh

function exit_trap()
{
    trap - INT TERM EXIT QUIT ABRT
    logger_Info "update_software_CRL exit pid: $$"
}

function verify_parameters()
{
    if [[ -z "$CRL_PATH" ]]; then
        logger_Error "some parameter is missing: crlPath can not be null"
        return ${ret_failed_param_wrong}
    fi

    if [[ ! -f "$CRL_PATH" ]]; then
        logger_Error "crlPath $(basename "${CRL_PATH}") do not exist"
        return ${ret_failed_param_wrong}
    fi

    # 判断文件是不是以.crl文件结尾
    crl_path_lower=`echo "$CRL_PATH" | tr "[A-Z]" "[a-z]"`
    if [[ "$crl_path_lower" != *.crl ]]; then
        logger_Error "the file ($(basename "${CRL_PATH}")) is not a crl file"
        return ${ret_failed_param_wrong}
    fi

    # 判断文件大小，必须小于等于32k,且大于0
    crl_size=`stat -c "%s" ${CRL_PATH}`
    if [[ ${crl_size} -gt ${CRL_MAXSIZE} || ! -s ${CRL_PATH} ]]; then
        logger_Error "the ($(basename "${CRL_PATH}")) file size is not valid"
        return ${ret_failed_param_wrong}
    fi

    return ${ret_ok}
}

function verify_save_crl()
{
    # 判断本地是否已经存在已经导入了的吊销列表crl文件
    if [[ -f ${SAVE_CRL_PATH}/${SAVE_CRL_FILE_NAME} ]]; then
        local_exist_crl_handle
        ret=$?
        if [[ ${ret} != ${ret_crl_need_update} ]] ;then
            return ${ret}
        fi
    fi
    verify_and_update_local_crl
    return $?
}

function local_exist_crl_handle()
{
    local_crl_file=${SAVE_CRL_PATH}/${SAVE_CRL_FILE_NAME}
    # 首先校验本地文件是否合法
    verify_crl_file ${local_crl_file}
    ret=$?
    if [[ ${ret} != ${ret_ok} ]]; then
        logger_Info "The local crl file self verify failed"
        return ${ret_crl_need_update}
    fi
    logger_Info "The local crl file self verify success"
    # 本地文件校验成功，则比较两个文件的新旧
    compare_two_crl_file ${CRL_PATH} ${local_crl_file}
    ret=$?
    case ${ret} in
        ${STATE_SAME})
            if [[ "$(realpath ${CRL_PATH})" == "$(realpath ${SAVE_CRL_PATH}/${SAVE_CRL_FILE_NAME})" ]]; then
                # 如果传入的就是要保存的，直接校验成功即可
                logger_Info "The imported crl file ($(basename "${CRL_PATH}")) verify success and save crl success!"
                return ${ret_ok}
            fi
            logger_Warn "import crl failed: The imported crl file ($(basename "${CRL_PATH}")) is the same to the existed CRL file, no need update!"
            return ${ret_failed_crl_same_old_crl}
            ;;
        ${STATE_NEW})
            logger_Info "The imported crl file ($(basename "${CRL_PATH}")) is newer than the existed CRL file, start to update."
            return ${ret_crl_need_update}
            ;;
        ${STATE_OLD})
            logger_Error "import crl failed: The imported crl file ($(basename "${CRL_PATH}")) update time is older than the existed CRL file, can not be updated."
            return ${ret_failed_crl_compare_update_time}
            ;;
        *)
            logger_Error "import crl failed: The imported crl file ($(basename "${CRL_PATH}")) verify failed, please check the crl file."
            return ${ret_failed_crl_format_check}
            ;;
    esac

}

function verify_and_update_local_crl()
{
    verify_crl_file ${CRL_PATH}
    ret=$?
    if [[ ${ret} != ${ret_ok} ]]; then
        logger_Error "import crl failed: The imported crl file ($(basename "${CRL_PATH}")) verify failed, please check the crl file"
        return ${ret_failed_crl_format_check}
    fi
    update_local_crl_file
    return $?
}

function verify_crl_file()
{
    # 校验传入crl文件同文件进行比较，校验过程会结合根证书对合法性进行校验，且比较结果为same
    crl_file=$1
    compare_two_crl_file ${crl_file} ${crl_file}
    ret=$?
    if [[ ${ret} == ${STATE_SAME} ]]; then
        return ${ret_ok}
    fi
    return ${ret_failed_verify_crl}
}

function compare_two_crl_file()
{
    new_crl_file=$1
    old_crl_file=$2
    # 需要比较待升级的crl与本地的crl谁更新，始终使用最新的crl
    ${WORK_PATH}/software/libs/ld-linux-aarch64.so.1 --library-path ${WORK_PATH}/software/libs/ ${WORK_PATH}/software/bin/verify_tool ${new_crl_file} ${old_crl_file}
    ret=$?
    logger_Info "Compare crl ($(basename ${new_crl_file})) with ($(basename ${old_crl_file})) result: ${ret} (0=STATE_SAME  1=STATE_NEW  2=STATE_OLD,  others is error code)"
    return ${ret}
}

function update_local_crl_file()
{
    if [[ ! -d ${SAVE_CRL_PATH} ]]; then
        mkdir -p ${SAVE_CRL_PATH}
    fi
    chown root:root ${SAVE_CRL_PATH}
    chmod 755 ${SAVE_CRL_PATH}
    # 保存新的crl文件，到固定目录下
    cp -f ${CRL_PATH} ${SAVE_CRL_PATH}/${SAVE_CRL_FILE_NAME}
    cp_ret=$?
    if [[ ${cp_ret} != 0 ]]; then
        logger_Error "import crl failed: Copy the imported crl file ($(basename "${CRL_PATH}")) failed, ret: ${cp_ret}"
        return ${ret_failed_crl_update}
    fi
    chown root:root ${SAVE_CRL_PATH}/${SAVE_CRL_FILE_NAME}
    chmod 644 ${SAVE_CRL_PATH}/${SAVE_CRL_FILE_NAME}
    logger_Info "The imported crl file ($(basename "${CRL_PATH}")) verify success and save crl success!"
    return ${ret_ok}
}

function usage()
{
    echo "update_software_CRL -- update software CRL file"
    echo "parameters:"
    echo "    --crlPath             crl file to import"
    echo "    -h, --help"
    echo "usage:"
    echo "    ./update_software_CRL.sh --crlPath=/tmp/newCrl.crl"
}

function import_software_crl()
{
    # 校验参数
    verify_parameters
    ret=$?
    if [[ "$ret" != "$ret_ok" ]]; then
        logger_Warn "verify input parameters failed, ret is $ret, exit crl import"
        return ${ret}
    fi
    # 校验crl文件是否合法
    verify_save_crl
    ret=$?
    if [[ "$ret" != "$ret_ok" ]]; then
        logger_Warn "verify and save crl failed, ret is $ret, exit crl import"
        return ${ret}
    fi
    logger_Info "Import crl success!"
    if [[ "${CRL_PATH}" != "${SAVE_CRL_PATH}/${SAVE_CRL_FILE_NAME}" ]]; then
        logger_Info "Please remove your crl file ($(basename "${CRL_PATH}")), if you do not need it"
    fi
    return ${ret_ok}
}

function main()
{
    trap exit_trap INT TERM EXIT QUIT ABRT
    logger_Info "update software crl begin pid: $$, cmd params: ${*}"
    ARGS=$(getopt -o h -a -l crlPath:,help -n "update_software_CRL.sh" -- "$@")
    if [[ $? != 0 ]]; then
        logger_Warn "Terminating....." >&2
        exit ${ret_failed_param_wrong}
    fi

    eval set -- "${ARGS}"

    while true; do
        case $1 in
            --crlPath)
                CRL_PATH="$2"
                ;;
            --help | -h)
                usage
                exit ${ret_failed_param_wrong}
                ;;
            --)
                shift
                if [[ ! -z "$@" ]]; then
                    logger_Warn "too many arguments"
                    exit ${ret_failed_param_wrong}
                fi
                break
                ;;
            *)
                logger_Warn "unkown argument: $OPTARG args:$@"
                exit ${ret_failed_param_wrong}
                ;;
        esac
        shift 2
    done
    import_software_crl
    return $?
}

main "$@"
RESULT=$?
exit ${RESULT}
